package com.yupi.yupicturebackend.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import com.yupi.yupicturebackend.model.dto.picture.BatchProcessConfig;
import com.yupi.yupicturebackend.model.dto.picture.FilterConfig;
import com.yupi.yupicturebackend.model.dto.picture.ProcessResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.*;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * 图片批量处理工具类
 * 
 * <p>提供批量压缩、格式转换、尺寸调整、滤镜应用等功能</p>
 * 
 * @author yupi
 */
@Slf4j
@Component
public class PictureBatchProcessUtils {

    private static final ExecutorService THREAD_POOL = Executors.newFixedThreadPool(10);

    /**
     * 批量压缩图片
     *
     * @param imageUrls 图片URL列表
     * @param quality 压缩质量 (0.1-1.0)
     * @return 处理结果
     */
    public static Map<String, ProcessResult> batchCompress(List<String> imageUrls, float quality) {
        if (CollUtil.isEmpty(imageUrls)) {
            return new HashMap<>();
        }

        List<CompletableFuture<Map.Entry<String, ProcessResult>>> futures = imageUrls.stream()
            .map(url -> CompletableFuture.supplyAsync(() -> {
                try {
                    byte[] compressedData = compressImage(url, quality);
                    ProcessResult result = new ProcessResult();
                    result.setSuccess(compressedData != null);
                    result.setProcessedData(compressedData);
                    result.setOriginalUrl(url);
                    result.setProcessType("compress");
                    return new AbstractMap.SimpleEntry<>(url, result);
                } catch (Exception e) {
                    log.error("压缩图片失败: {}", url, e);
                    ProcessResult result = new ProcessResult();
                    result.setSuccess(false);
                    result.setErrorMessage(e.getMessage());
                    result.setOriginalUrl(url);
                    return new AbstractMap.SimpleEntry<>(url, result);
                }
            }, THREAD_POOL))
            .collect(Collectors.toList());

        return futures.stream()
            .map(CompletableFuture::join)
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    }

    /**
     * 批量调整图片尺寸
     *
     * @param imageUrls 图片URL列表
     * @param targetWidth 目标宽度
     * @param targetHeight 目标高度
     * @param keepAspectRatio 是否保持宽高比
     * @return 处理结果
     */
    public static Map<String, ProcessResult> batchResize(List<String> imageUrls, int targetWidth, int targetHeight, boolean keepAspectRatio) {
        if (CollUtil.isEmpty(imageUrls)) {
            return new HashMap<>();
        }

        List<CompletableFuture<Map.Entry<String, ProcessResult>>> futures = imageUrls.stream()
            .map(url -> CompletableFuture.supplyAsync(() -> {
                try {
                    byte[] resizedData = resizeImage(url, targetWidth, targetHeight, keepAspectRatio);
                    ProcessResult result = new ProcessResult();
                    result.setSuccess(resizedData != null);
                    result.setProcessedData(resizedData);
                    result.setOriginalUrl(url);
                    result.setProcessType("resize");
                    return new AbstractMap.SimpleEntry<>(url, result);
                } catch (Exception e) {
                    log.error("调整图片尺寸失败: {}", url, e);
                    ProcessResult result = new ProcessResult();
                    result.setSuccess(false);
                    result.setErrorMessage(e.getMessage());
                    result.setOriginalUrl(url);
                    return new AbstractMap.SimpleEntry<>(url, result);
                }
            }, THREAD_POOL))
            .collect(Collectors.toList());

        return futures.stream()
            .map(CompletableFuture::join)
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    }

    /**
     * 批量格式转换
     *
     * @param imageUrls 图片URL列表
     * @param targetFormat 目标格式 (jpg, png, webp, gif)
     * @return 处理结果
     */
    public static Map<String, ProcessResult> batchConvertFormat(List<String> imageUrls, String targetFormat) {
        if (CollUtil.isEmpty(imageUrls)) {
            return new HashMap<>();
        }

        List<CompletableFuture<Map.Entry<String, ProcessResult>>> futures = imageUrls.stream()
            .map(url -> CompletableFuture.supplyAsync(() -> {
                try {
                    byte[] convertedData = convertImageFormat(url, targetFormat);
                    ProcessResult result = new ProcessResult();
                    result.setSuccess(convertedData != null);
                    result.setProcessedData(convertedData);
                    result.setOriginalUrl(url);
                    result.setProcessType("convert");
                    result.setTargetFormat(targetFormat);
                    return new AbstractMap.SimpleEntry<>(url, result);
                } catch (Exception e) {
                    log.error("转换图片格式失败: {}", url, e);
                    ProcessResult result = new ProcessResult();
                    result.setSuccess(false);
                    result.setErrorMessage(e.getMessage());
                    result.setOriginalUrl(url);
                    return new AbstractMap.SimpleEntry<>(url, result);
                }
            }, THREAD_POOL))
            .collect(Collectors.toList());

        return futures.stream()
            .map(CompletableFuture::join)
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    }

    /**
     * 批量应用滤镜
     *
     * @param imageUrls 图片URL列表
     * @param filterConfig 滤镜配置
     * @return 处理结果
     */
    public static Map<String, ProcessResult> batchApplyFilter(List<String> imageUrls, FilterConfig filterConfig) {
        if (CollUtil.isEmpty(imageUrls)) {
            return new HashMap<>();
        }

        List<CompletableFuture<Map.Entry<String, ProcessResult>>> futures = imageUrls.stream()
            .map(url -> CompletableFuture.supplyAsync(() -> {
                try {
                    byte[] filteredData = applyFilter(url, filterConfig);
                    ProcessResult result = new ProcessResult();
                    result.setSuccess(filteredData != null);
                    result.setProcessedData(filteredData);
                    result.setOriginalUrl(url);
                    result.setProcessType("filter");
                    result.setFilterType(filterConfig.getFilterType());
                    return new AbstractMap.SimpleEntry<>(url, result);
                } catch (Exception e) {
                    log.error("应用滤镜失败: {}", url, e);
                    ProcessResult result = new ProcessResult();
                    result.setSuccess(false);
                    result.setErrorMessage(e.getMessage());
                    result.setOriginalUrl(url);
                    return new AbstractMap.SimpleEntry<>(url, result);
                }
            }, THREAD_POOL))
            .collect(Collectors.toList());

        return futures.stream()
            .map(CompletableFuture::join)
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    }

    /**
     * 综合批量处理
     *
     * @param imageUrls 图片URL列表
     * @param batchConfig 批量处理配置
     * @return 处理结果
     */
    public static Map<String, ProcessResult> batchProcess(List<String> imageUrls, BatchProcessConfig batchConfig) {
        if (CollUtil.isEmpty(imageUrls)) {
            return new HashMap<>();
        }

        List<CompletableFuture<Map.Entry<String, ProcessResult>>> futures = imageUrls.stream()
            .map(url -> CompletableFuture.supplyAsync(() -> {
                try {
                    BufferedImage image = ImageIO.read(new URL(url));
                    BufferedImage processedImage = image;

                    // 1. 调整尺寸
                    if (batchConfig.isEnableResize()) {
                        processedImage = resizeBufferedImage(processedImage, 
                            batchConfig.getTargetWidth(), 
                            batchConfig.getTargetHeight(), 
                            batchConfig.isKeepAspectRatio());
                    }

                    // 2. 应用滤镜
                    if (batchConfig.isEnableFilter() && batchConfig.getFilterConfig() != null) {
                        processedImage = applyFilterToImage(processedImage, batchConfig.getFilterConfig());
                    }

                    // 3. 调整亮度对比度
                    if (batchConfig.isEnableBrightnessContrast()) {
                        processedImage = adjustBrightnessContrast(processedImage, 
                            batchConfig.getBrightness(), 
                            batchConfig.getContrast());
                    }

                    // 4. 转换格式并压缩
                    byte[] finalData = convertAndCompress(processedImage, 
                        batchConfig.getTargetFormat(), 
                        batchConfig.getQuality());

                    ProcessResult result = new ProcessResult();
                    result.setSuccess(true);
                    result.setProcessedData(finalData);
                    result.setOriginalUrl(url);
                    result.setProcessType("batch");
                    result.setProcessSteps(Arrays.asList("resize", "filter", "brightness", "compress"));
                    
                    return new AbstractMap.SimpleEntry<>(url, result);
                    
                } catch (Exception e) {
                    log.error("批量处理图片失败: {}", url, e);
                    ProcessResult result = new ProcessResult();
                    result.setSuccess(false);
                    result.setErrorMessage(e.getMessage());
                    result.setOriginalUrl(url);
                    return new AbstractMap.SimpleEntry<>(url, result);
                }
            }, THREAD_POOL))
            .collect(Collectors.toList());

        return futures.stream()
            .map(CompletableFuture::join)
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    }

    /**
     * 生成缩略图
     *
     * @param imageUrls 图片URL列表
     * @param thumbnailSize 缩略图尺寸
     * @return 处理结果
     */
    public static Map<String, ProcessResult> batchGenerateThumbnails(List<String> imageUrls, int thumbnailSize) {
        return batchResize(imageUrls, thumbnailSize, thumbnailSize, true);
    }

    /**
     * 批量添加边框
     *
     * @param imageUrls 图片URL列表
     * @param borderWidth 边框宽度
     * @param borderColor 边框颜色
     * @return 处理结果
     */
    public static Map<String, ProcessResult> batchAddBorder(List<String> imageUrls, int borderWidth, String borderColor) {
        if (CollUtil.isEmpty(imageUrls)) {
            return new HashMap<>();
        }

        List<CompletableFuture<Map.Entry<String, ProcessResult>>> futures = imageUrls.stream()
            .map(url -> CompletableFuture.supplyAsync(() -> {
                try {
                    byte[] borderedData = addBorder(url, borderWidth, borderColor);
                    ProcessResult result = new ProcessResult();
                    result.setSuccess(borderedData != null);
                    result.setProcessedData(borderedData);
                    result.setOriginalUrl(url);
                    result.setProcessType("border");
                    return new AbstractMap.SimpleEntry<>(url, result);
                } catch (Exception e) {
                    log.error("添加边框失败: {}", url, e);
                    ProcessResult result = new ProcessResult();
                    result.setSuccess(false);
                    result.setErrorMessage(e.getMessage());
                    result.setOriginalUrl(url);
                    return new AbstractMap.SimpleEntry<>(url, result);
                }
            }, THREAD_POOL))
            .collect(Collectors.toList());

        return futures.stream()
            .map(CompletableFuture::join)
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    }

    // ==================== 私有辅助方法 ====================

    /**
     * 压缩单张图片
     */
    private static byte[] compressImage(String imageUrl, float quality) throws IOException {
        BufferedImage image = ImageIO.read(new URL(imageUrl));
        
        // 简化的压缩实现，实际应该使用更高级的压缩算法
        int newWidth = (int) (image.getWidth() * Math.sqrt(quality));
        int newHeight = (int) (image.getHeight() * Math.sqrt(quality));
        
        BufferedImage compressedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = compressedImage.createGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g2d.drawImage(image, 0, 0, newWidth, newHeight, null);
        g2d.dispose();
        
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(compressedImage, "jpg", baos);
        return baos.toByteArray();
    }

    /**
     * 调整单张图片尺寸
     */
    private static byte[] resizeImage(String imageUrl, int targetWidth, int targetHeight, boolean keepAspectRatio) throws IOException {
        BufferedImage image = ImageIO.read(new URL(imageUrl));
        BufferedImage resizedImage = resizeBufferedImage(image, targetWidth, targetHeight, keepAspectRatio);
        
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(resizedImage, "png", baos);
        return baos.toByteArray();
    }

    /**
     * 调整BufferedImage尺寸
     */
    private static BufferedImage resizeBufferedImage(BufferedImage image, int targetWidth, int targetHeight, boolean keepAspectRatio) {
        int newWidth = targetWidth;
        int newHeight = targetHeight;
        
        if (keepAspectRatio) {
            double aspectRatio = (double) image.getWidth() / image.getHeight();
            if (targetWidth / aspectRatio <= targetHeight) {
                newHeight = (int) (targetWidth / aspectRatio);
            } else {
                newWidth = (int) (targetHeight * aspectRatio);
            }
        }
        
        BufferedImage resizedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = resizedImage.createGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g2d.drawImage(image, 0, 0, newWidth, newHeight, null);
        g2d.dispose();
        
        return resizedImage;
    }

    /**
     * 转换图片格式
     */
    private static byte[] convertImageFormat(String imageUrl, String targetFormat) throws IOException {
        BufferedImage image = ImageIO.read(new URL(imageUrl));
        
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(image, targetFormat.toLowerCase(), baos);
        return baos.toByteArray();
    }

    /**
     * 应用滤镜
     */
    private static byte[] applyFilter(String imageUrl, FilterConfig filterConfig) throws IOException {
        BufferedImage image = ImageIO.read(new URL(imageUrl));
        BufferedImage filteredImage = applyFilterToImage(image, filterConfig);
        
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(filteredImage, "png", baos);
        return baos.toByteArray();
    }

    /**
     * 对BufferedImage应用滤镜
     */
    private static BufferedImage applyFilterToImage(BufferedImage image, FilterConfig filterConfig) {
        switch (filterConfig.getFilterType().toLowerCase()) {
            case "blur":
                return applyBlurFilter(image, filterConfig.getIntensity());
            case "sharpen":
                return applySharpenFilter(image, filterConfig.getIntensity());
            case "grayscale":
                return applyGrayscaleFilter(image);
            case "sepia":
                return applySepiaFilter(image);
            case "vintage":
                return applyVintageFilter(image);
            default:
                return image;
        }
    }

    /**
     * 应用模糊滤镜
     */
    private static BufferedImage applyBlurFilter(BufferedImage image, float intensity) {
        int radius = Math.max(1, (int) (intensity * 5));
        float[] matrix = new float[radius * radius];
        Arrays.fill(matrix, 1.0f / (radius * radius));
        
        Kernel kernel = new Kernel(radius, radius, matrix);
        ConvolveOp op = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
        return op.filter(image, null);
    }

    /**
     * 应用锐化滤镜
     */
    private static BufferedImage applySharpenFilter(BufferedImage image, float intensity) {
        float[] sharpenMatrix = {
            0, -intensity, 0,
            -intensity, 1 + 4 * intensity, -intensity,
            0, -intensity, 0
        };
        
        Kernel kernel = new Kernel(3, 3, sharpenMatrix);
        ConvolveOp op = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
        return op.filter(image, null);
    }

    /**
     * 应用灰度滤镜
     */
    private static BufferedImage applyGrayscaleFilter(BufferedImage image) {
        BufferedImage grayImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
        Graphics2D g2d = grayImage.createGraphics();
        g2d.drawImage(image, 0, 0, null);
        g2d.dispose();
        return grayImage;
    }

    /**
     * 应用怀旧滤镜
     */
    private static BufferedImage applySepiaFilter(BufferedImage image) {
        BufferedImage sepiaImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
        
        for (int x = 0; x < image.getWidth(); x++) {
            for (int y = 0; y < image.getHeight(); y++) {
                Color color = new Color(image.getRGB(x, y));
                
                int tr = (int) (0.393 * color.getRed() + 0.769 * color.getGreen() + 0.189 * color.getBlue());
                int tg = (int) (0.349 * color.getRed() + 0.686 * color.getGreen() + 0.168 * color.getBlue());
                int tb = (int) (0.272 * color.getRed() + 0.534 * color.getGreen() + 0.131 * color.getBlue());
                
                tr = Math.min(255, tr);
                tg = Math.min(255, tg);
                tb = Math.min(255, tb);
                
                sepiaImage.setRGB(x, y, new Color(tr, tg, tb).getRGB());
            }
        }
        
        return sepiaImage;
    }

    /**
     * 应用复古滤镜
     */
    private static BufferedImage applyVintageFilter(BufferedImage image) {
        // 先应用怀旧效果，再降低饱和度
        BufferedImage vintageImage = applySepiaFilter(image);
        return adjustBrightnessContrast(vintageImage, -0.1f, 0.8f);
    }

    /**
     * 调整亮度和对比度
     */
    private static BufferedImage adjustBrightnessContrast(BufferedImage image, float brightness, float contrast) {
        BufferedImage adjustedImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
        
        for (int x = 0; x < image.getWidth(); x++) {
            for (int y = 0; y < image.getHeight(); y++) {
                Color color = new Color(image.getRGB(x, y));
                
                int r = (int) Math.max(0, Math.min(255, (color.getRed() - 128) * contrast + 128 + brightness * 255));
                int g = (int) Math.max(0, Math.min(255, (color.getGreen() - 128) * contrast + 128 + brightness * 255));
                int b = (int) Math.max(0, Math.min(255, (color.getBlue() - 128) * contrast + 128 + brightness * 255));
                
                adjustedImage.setRGB(x, y, new Color(r, g, b).getRGB());
            }
        }
        
        return adjustedImage;
    }

    /**
     * 转换格式并压缩
     */
    private static byte[] convertAndCompress(BufferedImage image, String format, float quality) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(image, format.toLowerCase(), baos);
        return baos.toByteArray();
    }

    /**
     * 添加边框
     */
    private static byte[] addBorder(String imageUrl, int borderWidth, String borderColor) throws IOException {
        BufferedImage image = ImageIO.read(new URL(imageUrl));
        
        int newWidth = image.getWidth() + 2 * borderWidth;
        int newHeight = image.getHeight() + 2 * borderWidth;
        
        BufferedImage borderedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = borderedImage.createGraphics();
        
        // 绘制边框
        g2d.setColor(Color.decode(borderColor));
        g2d.fillRect(0, 0, newWidth, newHeight);
        
        // 绘制原图
        g2d.drawImage(image, borderWidth, borderWidth, null);
        g2d.dispose();
        
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(borderedImage, "png", baos);
        return baos.toByteArray();
    }
}
